/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package antcolony;

import java.util.*;
import DeMaSoft.*;

/**
 *
 * @author Fernando
 */
public class Ant {

    private boolean _done = false;
    private Node _initialNode;
    private int _initialCapacity;
    private int _currentCapacity;
    private ArrayList<Node> _route;
    private float _speed;
    private float _fuelConsumedPerKm = (float)1;
    private static final float Q = (float)0.9;
    private static final float BETA = 1;

    public Ant(Vehicle v) {
        this._initialCapacity = v.getCapacidadActual();
        this._currentCapacity = v.getCapacidadActual();
        this._initialNode = AntColony.nodeMap.get(v.getPosicion().getPosX()*RouteCalculator.mapa.getAlto() + v.getPosicion().getPosY());
        this._route = new ArrayList<>();
        this._route.add(_initialNode);
        this._speed = v.getVelocidadMaxima();
        this._done = false;
    }

    public boolean isDone() {
        return _done;
    }

    private float calculateTrailImportance(Node node, PheromoneMatrix pheromoneArcs) {//según la feromona
        return pheromoneArcs.getLevel(_route.get(_route.size() - 1), node);
    }

    public ArrayList<Node> getRoute() {
        return _route;
    }

    private float calculateTrailAtractiveness(Node node) {

        Node actualNode = _route.get(_route.size()-1);
        float distance = Node.geomDistance(actualNode, node);
        float combustible = distance * _fuelConsumedPerKm;
        float tiempo = distance / _speed;
        int prioridad = node.getActualTimeWindow();
        /*
        float horaExtra=0;        
        Reloj reloj= Reloj.getInstancia();
        Node n = new Node();
        n.setX(RouteCalculator.almacen.getUbicacion().getPosX());
        n.setY(RouteCalculator.almacen.getUbicacion().getPosY());
       float tiempo2= Node.geomDistance(node, n)/_speed;
       
       if (reloj.getHoraActual()<8){
           
           if (tiempo+tiempo2>=8)horaExtra=(tiempo+tiempo2-8)*ConstantesDeCosto.COSTOHORAEXTRA;
           
       }else{
           
           if (reloj.getHoraActual()<16){
               if (tiempo+tiempo2>=16)horaExtra=(tiempo+tiempo2-16)*ConstantesDeCosto.COSTOHORAEXTRA;
               
           }else{
               if (reloj.getHoraActual()>=16){
                   if (tiempo+tiempo2>=24)horaExtra=(tiempo+tiempo2-24)*ConstantesDeCosto.COSTOHORAEXTRA;
                   
               }
               
           }
           
       }*/
        
        return 1/combustible * 1/tiempo * 1/prioridad;// * 1/horaExtra;

    }

    private boolean isPossible(Node nextNode) {//toda esta parte ha de ser re planteada
        return true;

    }

    public float calculateRouteCost() {
        //falta calcular el costo de forma mas precisa
        float cost = 0;
        int tamRoute=_route.size();
        for (int i = 1; i < tamRoute; i++) {
            cost += Node.geomDistance(_route.get(i - 1), _route.get(i));
        }

        return cost;
    }

    public void selectNextDestination(ArrayList<Node> orders, PheromoneMatrix pheromoneArcs) {
        if(this.isDone())return;
        float sum =0;
        int tam = orders.size();
        Node selected = null;
        float max =0;
        int maxIndex =0;
        Node nextNode; 
        ArrayList<Float> probAcum = new ArrayList<>(); 
        for(int i =0; i< tam ;i++ ){
            nextNode = orders.get(i);
            if(!isPossible(nextNode)){
                probAcum.add(sum);
                continue;
            }
            //que tan frecuente se ha pasado por esa opcion por otras hormigas?
            float t = calculateTrailImportance(nextNode, pheromoneArcs);
            //que tan atractiva es la solucion en terminos de distancia, tiempo y combustible?
            float n = calculateTrailAtractiveness(nextNode);
            float product = (float) (t * Math.pow(n, BETA));
            probAcum.add(sum);
            sum += product;
            if(product > max){
                max = product;
                maxIndex = i;
            }

        }
        if(probAcum.get(probAcum.size()-1)==0){
            this._done=true;
            return;
        }
        if(Math.random() <= Q){
            selected = orders.get(maxIndex);
        }
        else{
            float p = (float)(Math.random()*probAcum.get(probAcum.size()-1));
            for (int i = 0; i < probAcum.size(); i++) {
                if (p <= probAcum.get(i)) {
                    selected = orders.get(i);
                    break;
                }
            }
        }
        if(selected == null){
            selected = orders.get(maxIndex);
        }
        //actualizar capacidadlected, this._route.get(this._route.size()-1)) * this._fuelConsumedPerKm;
        if(this._currentCapacity < selected.getDemand()){
            this._currentCapacity = 0;
            this._done=true;
        }
        else{
            this._currentCapacity-=selected.getDemand();
        }
        this._route.add(selected);
        orders.remove(selected);      
    }
    public int getInitialCapacity() {
        return _initialCapacity;
    }

    public void setInitialCapacity(int initialCapacity) {
        this._initialCapacity = initialCapacity;
    }
}
